//
//  SnakeBody.c
//  SnakeGame
//
//  Created by Hansuck Shim on 2014. 3. 23..
//  Copyright (c) 2014년 Hansuck Shim. All rights reserved.
//

#include "SnakeBody.h"

#include <stdio.h>  // debug & NULL
#include <stdlib.h> // malloc
#include <string.h> // memset

#include "Map.h"

struct SSnakeBodyNode* AllocSnakeBody(void)
{
    struct SSnakeBodyNode *pNode = (struct SSnakeBodyNode*)malloc( sizeof(struct SSnakeBodyNode) );
    if( pNode != NULL )
        memset( pNode, 0, sizeof(struct SSnakeBodyNode) );
    
    return pNode;
}

void AppendSnakeBody( struct SSnakeBodyNode *pNode )
{
    if( pNode == NULL )
    {
        printf("[AppendSnakeBody] failed: pNode is NULL\r\n");
        return;
    }
    
    if( g_pSnake == NULL )
    {
        g_pSnake = pNode;
        return;
    }
    else
    {
        struct SSnakeBodyNode *pFindTail = g_pSnake;
        
        while( pFindTail != NULL )
        {
            if( pFindTail->pNext == NULL )
                break;
            
            pFindTail = pFindTail->pNext;
        }
        
        pFindTail->pNext = pNode;
    }
}

void ResetSnakeBody( unsigned int uCnt )
{
    if( g_pSnake == NULL )
    {
        printf("[ResetSnakeBody] failed: g_pSnake is NULL\r\n");
        return;
    }
    
    struct SSnakeBodyNode *pNode = g_pSnake;
    struct SSnakeBodyNode *pNext = NULL;
    unsigned int ui = 0;
    
    // find starting node of free
    while( pNode != NULL && ui < uCnt )
    {
        if( (ui + 1) >= uCnt )
        {
            pNext = pNode->pNext;
            pNode->pNext = NULL;
            if( uCnt == 0 )
                free( pNode );
            pNode = pNext;
            break;
        }
        
        pNode = pNode->pNext;
        ++ui;
    }
    
    // free memory
    while( pNode != NULL )
    {
        pNext = pNode->pNext;
        free( pNode );
        pNode = pNext;
    }
}

void MoveSnake(void)
{
    if( g_nHeadDirX == 0 && g_nHeadDirY == 0 )
    {
        // there is no where to move
        return;
    }
    
    int arr_nX[2] = {0,0};
    int arr_nY[2] = {0,0};
    int nIdx = 0;
    struct SSnakeBodyNode *pNode = g_pSnake;
    struct SSnakeBodyNode *pNext = NULL;
    
    // head
    arr_nX[nIdx] = pNode->nX;
    arr_nY[nIdx] = pNode->nY;
    pNode->nX += g_nHeadDirX;
    pNode->nY += g_nHeadDirY;
    pNode = pNode->pNext;
    
    // body
    while( pNode != NULL )
    {
        pNext = pNode->pNext;
        
        arr_nX[((nIdx+1)%2)] = pNode->nX;
        arr_nY[((nIdx+1)%2)] = pNode->nY;
        
        pNode->nX = arr_nX[nIdx];
        pNode->nY = arr_nY[nIdx];
        
        ++nIdx;
        if( nIdx == 2 ) nIdx = 0;
        
        pNode = pNext;
    }
}

int IsSnakeThere( unsigned int uX, unsigned int uY )
{
    if( g_pSnake == NULL )
    {
        printf("[IsSnakeThere] failed: g_pSnake is NULL\r\n");
        return SNAKE_IS_NOT_THERE;
    }
    
    struct SSnakeBodyNode *pNode = g_pSnake;
    while( pNode != NULL )
    {
        if( pNode->nX == uX && pNode->nY == uY )
            return SNAKE_IS_THERE;
        pNode = pNode->pNext;
    }
    
    return SNAKE_IS_NOT_THERE;
}

int CheckSnakeMovable(void)
{
    int nRet = SNAKE_UNMOVABLE;
    
    // check key is changed and update head dir
    if( (g_nHeadDirX != g_nKeyDirX || g_nHeadDirY != g_nKeyDirY) &&
       ((g_nHeadDirX == 0 || g_nKeyDirX == 0) && (g_nHeadDirY == 0 || g_nKeyDirY == 0)) )
    {
        g_nHeadDirX = g_nKeyDirX;
        g_nHeadDirY = g_nKeyDirY;
    }
    
    if( g_pSnake != NULL )
    {
        switch(g_arrGameMap[(g_pSnake->nY+g_nHeadDirY)][(g_pSnake->nX+g_nHeadDirX)])
        {
            case 0:
                nRet = SNAKE_MOVABLE_EMPTY;
                break;
            case 1:
                nRet = SNAKE_UNMOVABLE;
                break;
            case 2:
                nRet = SNAKE_MOVABLE_FOOD;
            default:
                break;
        }
        if( IsSnakeThere((g_pSnake->nX + g_nHeadDirX), (g_pSnake->nY + g_nHeadDirY)) == SNAKE_IS_THERE )
        {
            nRet = SNAKE_UNMOVABLE;
        }
    }
    
    return nRet;
}

int GetSnakeLength(void)
{
    int nLen = 0;
    struct SSnakeBodyNode *pNode = g_pSnake;
    if( pNode != NULL ) nLen = 1;
    
    while( pNode != NULL )
    {
        pNode = pNode->pNext;
        ++nLen;
    }
    
    return nLen;
}